import urllib,requests,urllib2,socket,time,mechanize
from Business import PluginSQL
from bs4 import BeautifulSoup
from urlparse import urlsplit,urlparse,urlunparse,urljoin
from socket import timeout


########################################################################
class Exploiter(object):
    """
    Classe responsavel por enviar os ataques e retornar o resultado gerado
    """
    #----------------------------------------------------------------------
    def __init__(self, url):
        """
        Construtor recebe a URL alvo
        """
        self.url = url
      
    #----------------------------------------------------------------------
    def mount_URLs (self):
        """
        Molda a URL para URLPARSE e inclui o protocolo HTTP caso o usuario nao informar
        """
        self.URL_Parse_Aux = urlparse(self.url)
        if self.URL_Parse_Aux.scheme == '':
            self.url_proto = "http://" + self.url
            self.URL_Parse_Original = urlparse(self.url_proto)      
        else:
            self.URL_Parse_Original = urlparse(self.url)
            
       
       # Cria as URLs:
       # - Original
       # - Sem atributos
       # - Base
        try:
            self.URL_Original = self.URL_Parse_Original.scheme + "://" + self.URL_Parse_Original.netloc + self.URL_Parse_Original.path + "?" + self.URL_Parse_Original.query
            
            self.URL_Sem_Atrib = self.URL_Parse_Original.scheme + "://" + self.URL_Parse_Original.netloc + self.URL_Parse_Original.path
            
            self.URL_Base = self.URL_Parse_Original.scheme + "://" + self.URL_Parse_Original.netloc
        except socket.error, e:
            return [("Socket Error"), (e)]
        
        # Cria a conexao com a URL informada
        try:
            self.html = urllib2.urlopen(self.URL_Original, timeout=3)		
        except socket.timeout, e:
            return [("Socket Error"), (e)]
        except urllib2.HTTPError, e:
            return [("HTTP Error"), (e)]
        except urllib2.URLError, e:
            return [("URL Error"), (e)]       
       
        return self.URL_Original
    
    
    #----------------------------------------------------------------------
    def get_URL_Base(self):
        """
        Retorna a URL Base
        """
        return self.URL_Base
    
    
    #----------------------------------------------------------------------
    def get_URL_Sem_Atrib(self):
        """
        Retorna a URL sem atributos
        """
        return self.URL_Sem_Atrib	    
    
    
    #----------------------------------------------------------------------
    def get_Server_Info (self):
        """
        Exibe informacoes do servidor web
        """
        self.b = str()  
        try:
            self.html = urllib2.urlopen (self.URL_Original, timeout=1)
            for header, value in self.html.headers.items():
                self.b +=header + ' : ' + value +'\n'
            return self.b
       
        except urllib2.HTTPError, e:
            return [("HTTP Error"), (e)]
   
    #----------------------------------------------------------------------
    def set_Plugin (self, plugin):
        """
        Seleciona Plugin
        """
        self.plugin = plugin
   
   
    #----------------------------------------------------------------------
    def send_Attack (self, url):
        """
        Metodo que envia ataque para o servidor
        """
        try:
            self.html_attack = urllib2.urlopen (url, timeout=3)
            self.bs = BeautifulSoup(self.html_attack.read(), 'lxml')
           
            return self.bs.decode_contents()
           
        except urllib2.HTTPError, e:
            return [("HTTP Error"), (e)]


    #----------------------------------------------------------------------
    def get_Form(self, url):
        """
        Verifica e retorna para os Plugins o objeto Mechanize, caso seja encontrado formularios na URL enviada
        """
        self.br = mechanize.Browser()
        
        self.br.set_handle_robots(False)   # Ignora robots
        self.br.set_handle_refresh(False)
        self.br.open (url, timeout=3)	# Cria conexao com a URL
        
        self.resultados = []
        
        try:
            self.br.select_form(nr=0)
            for control in self.br.form.controls:
                if control.name is not None:	# Exclui FORM None
                    self.resultados.append(control.name)
            
            
            return self.resultados
        except AttributeError as e:	# Erro gerado quando nao existe FORM selecionado
            return [("AttributeError"), (e)]
        except mechanize._mechanize.FormNotFoundError as e:	# Erro gerado quando nao existe FORM
            return [("FormNotFoundError"), (e)]
        
        return ["NAO_TEM"]


    #----------------------------------------------------------------------
    def get_Form_HTML(self, lista_com_forms_ataques):
        """
        Submete o formulario contendo o ataque
        
        Retorna o codigo-fonte HTML do ataque realizado para analise nos PLUGINS
        """
        self.form_nova_lista = []
        
        self.br = mechanize.Browser()
        self.br.open(lista_com_forms_ataques[0])
        self.br.select_form(nr=0)
        self.br.set_all_readonly(False)
        for forms_ataques in lista_com_forms_ataques[1]:
            self.br.form[forms_ataques[0]] = str(forms_ataques[1])
        
        self.br.submit()
        self.form_nova_lista.append([self.br.response().read(), lista_com_forms_ataques])
        
        return self.form_nova_lista	    
    

    #----------------------------------------------------------------------
    def gen_URL_Encode (self, url):
        """
        Retorna a URL Encode
        """
        print self.url_encode
       
   
    #----------------------------------------------------------------------  
    def execute_Crawler (self):
        """
        Funcao que extrai todos os links com query (GET) na pagina testada
        
        Retorna lista com as URL
        """
        self.br = mechanize.Browser()
        self.br.set_handle_robots(False)   # Ignora robots
        self.br.set_handle_refresh(False)  
        self.br.open(self.URL_Original, timeout=3)
        self.links = []
        self.targuets = []
        for link  in self.br.links():
            if link.url.startswith( '/'):
                self.links.append(self.URL_Base+link.url)
            else:
                self.links.append(self.URL_Base+"/"+link.url)
            
        for atrib in self.links:
            self.url_aux = urlparse(atrib)
            if self.url_aux.query != "":
                self.targuets.append (self.url_aux.scheme + "://" + self.url_aux.netloc + self.url_aux.path + "?" + self.url_aux.query)
            else:
                pass
        
        # Remove links duplicados
        self.targuets = list(set(self.targuets))
        return self.targuets


    #----------------------------------------------------------------------
    def get_All_Targets (self):
        """
        Extrai todos os alvos
        """
        self.lista_de_ataques = []
        self.lista_de_links = []
        
        # Inlui na lista de ataques caso a URL possua atributos 
        if (self.URL_Parse_Original.params != "") or (self.URL_Parse_Original.query != ""):
            self.lista_de_ataques.append(self.URL_Original)          
            
        # Inclui os links internos encontrados no Crawler na lista de ataques
        self.lista_de_links = self.execute_Crawler()
        
        for links in self.lista_de_links:
            self.lista_de_ataques.append(links)
        
        # Remove links duplicados
        self.lista_de_ataques = list(set(self.lista_de_ataques))
        
        return self.lista_de_ataques